home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / glimpse-2.1 / compress / uncast.c < prev   
Encoding:
C/C++ Source or Header  |  1995-05-16  |  18.5 KB  |  614 lines

  1. /* Copyright (c) 1994 Burra Gopal, Udi Manber.  All Rights Reserved. */
  2.  
  3. /*
  4.  * uncast.c:    main text uncompression routines. Exports tuncompress() called
  5.  *        from main() in main_uncast.c, and one other simple routine
  6.  *        tuncompressible_file().
  7.  */
  8.  
  9. #include "defs.h"
  10. #include <sys/time.h>
  11. #include <utime.h>
  12.  
  13. #define MYEOF    0xffffffff
  14.  
  15. extern int RESERVED_CHARS;
  16. extern int MAX_WORDS;
  17. extern int SPECIAL_WORDS;
  18. extern int BEGIN_SPECIAL_WORDS;
  19. extern int END_SPECIAL_WORDS;
  20. extern int NUM_SPECIAL_DELIMITERS;
  21. extern int END_SPECIAL_DELIMITERS;
  22. extern int ONE_VERBATIM;
  23. extern int TC_FOUND_BLANK, TC_FOUND_NOTBLANK;
  24. extern char comp_signature[SIGNATURE_LEN];
  25. extern hash_entry freq_words_table[MAX_WORD_LEN+2][256];    /* 256 is the maximum possible number of special words */
  26. extern char freq_words_strings[256][MAX_WORD_LEN+2];
  27. extern int freq_words_lens[256];
  28. extern char *compress_string_table[DEF_MAX_WORDS]; /*[MAX_WORD_LEN+2]; */
  29.  
  30. extern int usemalloc, next_free_strtable;
  31.  
  32. initialize_tuncompress(string_file, freq_file, flags)
  33.     char    *string_file, *freq_file;
  34.     int    flags;
  35. {
  36.     FILE    *stringfp;
  37.  
  38.     if (!initialize_common(freq_file, flags)) return 0;
  39.     next_free_strtable = 0;
  40.     memset(compress_string_table, '\0', sizeof(char *) * DEF_MAX_WORDS);
  41.     if (MAX_WORDS == 0) return 1;
  42.  
  43.     /* Load uncompress dictionary */
  44.     if ((stringfp = fopen(string_file, "r")) == NULL) {
  45.         if (flags & TC_ERRORMSGS) {
  46.             fprintf(stderr, "cannot open cast-dictionary file: %s\n", string_file);
  47.             fprintf(stderr, "(use -H to give a dictionary-dir or run 'buildcast' to make a dictionary)\n");
  48.         }
  49.         return 0;
  50.     }
  51.     if (!build_string(compress_string_table, stringfp, -1, 0)) {    /* read all bytes until end */
  52.         fclose(stringfp);
  53.         return 0;
  54.     }
  55.     fclose(stringfp);
  56.     return 1;
  57. }
  58.  
  59. uninitialize_tuncompress()
  60. {
  61.     int    i;
  62.  
  63.     uninitialize_common();
  64.     if (usemalloc) {
  65.         for (i=0; i<MAX_WORDS; i++) {
  66.             if (compress_string_table[i] != NULL) free(compress_string_table[i]);
  67.         }
  68.     }
  69.     memset(compress_string_table, '\0', sizeof(char *) * DEF_MAX_WORDS);
  70.     next_free_strtable = 0;
  71. }
  72.  
  73. extern int initialize_common_done;
  74.  
  75. /* TRUE if file has the signature in its first 15 bytes, false otherwise */
  76. int
  77. tuncompressible(buffer, num_read)
  78.     char    *buffer;
  79.     int    num_read;
  80. {
  81.     char    *sig = comp_signature;
  82.     int    i;
  83.  
  84.     if (!initialize_common_done) return 0;
  85.     if (num_read < SIGNATURE_LEN - 1) return 0;
  86.     for (i=0; i<SIGNATURE_LEN - 1; i++)
  87.         if (buffer[i] != sig[i]) return 0;
  88.     return 1;
  89.     /* a rewind is not done. hence this is useful even for stdin */
  90. }
  91.  
  92. int
  93. tuncompressible_filename(name, len)
  94.     char    *name;
  95.     int    len;
  96. {
  97.     if (!initialize_common_done) return 0;
  98.     if ((len < strlen(COMP_SUFFIX) + 1) || (strcmp(&name[len-strlen(COMP_SUFFIX)], COMP_SUFFIX))) return 0;
  99.     return 1;
  100. }
  101.  
  102. int
  103. tuncompressible_file(name)
  104.     char    *name;
  105. {
  106.     char    buf[SIGNATURE_LEN + 2];
  107.     int    num;
  108.     FILE    *fp;
  109.  
  110.     if (!initialize_common_done) return 0;
  111.     if (!tuncompressible_filename(name, strlen(name))) return 0;
  112.     if ((fp = fopen(name, "r")) == NULL) return 0;
  113.     num = fread(buf, 1, SIGNATURE_LEN - 1, fp);
  114.     fclose(fp);
  115.     return(tuncompressible(buf, num));
  116. }
  117.  
  118. tuncompressible_fp(fp)
  119.     FILE    *fp;
  120. {
  121.     char    buf[SIGNATURE_LEN + 2];
  122.     int    num;
  123.  
  124.     if (!initialize_common_done) return 0;
  125.     num = fread(buf, 1, SIGNATURE_LEN - 1, fp);
  126.     return(tuncompressible(buf, num));
  127. }
  128.  
  129. /* defined in misc.c */
  130. extern char special_texts[];
  131. extern char special_delimiters[];
  132.  
  133. #define process_special_char(c)\
  134. {\
  135.     if (outfp != NULL) {\
  136.         switch(c)\
  137.         {\
  138.         case TWOBLANKS:\
  139.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  140.             putc(' ', outfp);\
  141.             outlen ++;\
  142.             putc(' ', outfp);\
  143.             outlen ++;\
  144.             break;\
  145.         case BLANK:\
  146.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  147.             putc(' ', outfp);\
  148.             outlen ++;\
  149.             break;\
  150. \
  151.         case TWOTABS:\
  152.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  153.             putc('\t', outfp);\
  154.             outlen ++;\
  155.             putc('\t', outfp);\
  156.             outlen ++;\
  157.             break;\
  158.         case TAB:\
  159.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  160.             putc('\t', outfp);\
  161.             outlen ++;\
  162.             break;\
  163. \
  164.         case TWONEWLINES:\
  165.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  166.             putc('\n', outfp);\
  167.             outlen ++;\
  168.             putc('\n', outfp);\
  169.             outlen ++;\
  170.             break;\
  171.         case NEWLINE:\
  172.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  173.             putc('\n', outfp);\
  174.             outlen ++;\
  175.             break;\
  176. \
  177.         default:\
  178.             if ((c < END_SPECIAL_TEXTS) && (c >= BEGIN_SPECIAL_TEXTS)) {\
  179.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  180.                 putc(special_texts[c - BEGIN_SPECIAL_TEXTS], outfp); outlen ++;\
  181.             }\
  182.             else if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {\
  183.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  184.                 putc(special_delimiters[c - BEGIN_SPECIAL_DELIMITERS], outfp); outlen ++;\
  185.             }\
  186.             else if ((c < END_SPECIAL_WORDS) && (c >= BEGIN_SPECIAL_WORDS)) {\
  187.                 if ((maxoutlen >= 0) && (outlen + freq_words_lens[c - BEGIN_SPECIAL_WORDS] >= maxoutlen)) return outlen;\
  188.                 fprintf(outfp, "%s", freq_words_strings[c - BEGIN_SPECIAL_WORDS]); outlen += freq_words_lens[c - BEGIN_SPECIAL_WORDS];\
  189.             }\
  190.             /* else should not have called this function */\
  191.         }\
  192.     }\
  193.     if (outbuf != NULL) {\
  194.         switch(c)\
  195.         {\
  196.         case TWOBLANKS:\
  197.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  198.             outbuf[outlen ++] = ' ';\
  199.             outbuf[outlen ++] = ' ';\
  200.             break;\
  201.         case BLANK:\
  202.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  203.             outbuf[outlen ++] = ' ';\
  204.             break;\
  205. \
  206.         case TWOTABS:\
  207.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  208.             outbuf[outlen ++] = '\t';\
  209.             outbuf[outlen ++] = '\t';\
  210.             break;\
  211.         case TAB:\
  212.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  213.             outbuf[outlen ++] = '\t';\
  214.             break;\
  215. \
  216.         case TWONEWLINES:\
  217.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  218.             outbuf[outlen ++] = '\n';\
  219.             outbuf[outlen ++] = '\n';\
  220.             break;\
  221.         case NEWLINE:\
  222.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  223.             outbuf[outlen ++] = '\n';\
  224.             break;\
  225. \
  226.         default:\
  227.             if ((c < END_SPECIAL_TEXTS) && (c >= BEGIN_SPECIAL_TEXTS)) {\
  228.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  229.                 outbuf[outlen ++] = special_texts[c - BEGIN_SPECIAL_TEXTS];\
  230.             }\
  231.             else if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {\
  232.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  233.                 outbuf[outlen ++] = special_delimiters[c - BEGIN_SPECIAL_DELIMITERS];\
  234.             }\
  235.             else if ((c < END_SPECIAL_WORDS) && (c >= BEGIN_SPECIAL_WORDS)) {\
  236.                 /* printf("-->%s\n", freq_words_strings[c-BEGIN_SPECIAL_WORDS]); */\
  237.                 if ((maxoutlen >= 0) && (outlen + freq_words_lens[c - BEGIN_SPECIAL_WORDS] >= maxoutlen)) return outlen;\
  238.                 memcpy(outbuf+outlen, freq_words_strings[c - BEGIN_SPECIAL_WORDS], freq_words_lens[c - BEGIN_SPECIAL_WORDS]);\
  239.                 outlen += freq_words_lens[c - BEGIN_SPECIAL_WORDS]; \
  240.             }\
  241.             /* else should not have called this function */\
  242.         }\
  243.     }\
  244. }
  245.  
  246. int UNCAST_ERRORS = 0;
  247.  
  248. /* Uncompresses input from indata and outputs it into outdata: returns number of chars in output */
  249. int
  250. tuncompress(indata, maxinlen, outdata, maxoutlen, flags)
  251.     void    *indata, *outdata;
  252.     int    maxinlen, maxoutlen;
  253.     int    flags;
  254. {
  255.     unsigned short    index, dindex;
  256.     unsigned int    c;
  257.     int    verbatim_state = 0;
  258.     int    inlen, outlen = 0;
  259.     FILE    *infp = NULL, *outfp = NULL;
  260.     unsigned char    *inbuf = NULL, *outbuf = NULL;
  261.     int    easysearch = flags&TC_EASYSEARCH;
  262.     int    untilnewline = flags&TC_UNTILNEWLINE;
  263.  
  264.     if (flags & TC_SILENT) return 0;
  265.     if (maxinlen < 0) {
  266.         infp = (FILE *)indata;
  267.         if ((easysearch = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;    /* ignore parameter: take from file */
  268.         inlen = SIGNATURE_LEN;
  269.     }
  270.     else {    /* don't care about signature: user's responsibility */
  271.         inbuf = (unsigned char *)indata;
  272.         inlen = 0;
  273.     }
  274.  
  275.     if (maxoutlen < 0) {
  276.         outfp = (FILE *)outdata;
  277.     }
  278.     else {
  279.         outbuf = (unsigned char *)outdata;
  280.     }
  281.  
  282.     if (easysearch) {
  283.         ONE_VERBATIM = EASY_ONE_VERBATIM;
  284.         NUM_SPECIAL_DELIMITERS = EASY_NUM_SPECIAL_DELIMITERS;
  285.         END_SPECIAL_DELIMITERS = EASY_END_SPECIAL_DELIMITERS;
  286.     }
  287.     else {
  288.         ONE_VERBATIM = HARD_ONE_VERBATIM;
  289.         NUM_SPECIAL_DELIMITERS = HARD_NUM_SPECIAL_DELIMITERS;
  290.         END_SPECIAL_DELIMITERS = HARD_END_SPECIAL_DELIMITERS;
  291.     }
  292.  
  293.     if (TC_FOUND_BLANK) {
  294.         if (outfp != NULL) putc(' ', outfp);
  295.         if (outbuf != NULL) outbuf[outlen] = ' ';
  296.         outlen ++;
  297.     }
  298.     TC_FOUND_BLANK = 0;    /* default: use result of previous backward_tcompressed_word only */
  299.  
  300.     /*
  301.      * The algorithm, as expected, is a complete inverse of the compression
  302.      * algorithm: see tcompress.c in this directory to understand this function.
  303.      * I've used gotos since the termination condition is too complex.
  304.      * The two sub-parts are exactly the same except for verbatim processing.
  305.      * Actually, loop-unrolling was done here: you can combine them together but...
  306.      */
  307.     if (easysearch)
  308.     {    /* compress was done in a context-free way to speed up searches */
  309.         while(1) {
  310.             if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  311.  
  312.         bypass_getc1:
  313.             if (c == ONE_VERBATIM) {
  314.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  315.                 if ((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  316.                 if (outfp != NULL) putc(c, outfp);    /* no processing whatsoever */
  317.                 if (outbuf != NULL) outbuf[outlen] = c;
  318.                 outlen ++;
  319.             }
  320.             else if (verbatim_state) {
  321.                 if (c == END_VERBATIM) verbatim_state = 0;
  322.                 else {
  323.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  324.                     if (outfp != NULL) putc(c, outfp);
  325.                     if (outbuf != NULL) outbuf[outlen] = c;
  326.                     outlen ++;
  327.                 }
  328.             }
  329.             else if (c < END_SPECIAL_CHARS) {
  330.                 process_special_char(c)
  331.                 if ( ((c == NEWLINE) || (c == TWONEWLINES)) && untilnewline)
  332.                     return outlen;
  333.             }
  334.             else if (c == BEGIN_VERBATIM) {
  335.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  336.                 if ((maxoutlen >= 0) && (outlen + 1>= maxoutlen)) return outlen;
  337.                 if (outfp != NULL) putc(c, outfp);
  338.                 if (outbuf != NULL) outbuf[outlen] = c;
  339.                 outlen ++;
  340.                 verbatim_state = 1;
  341.             }
  342.             else if (c == END_VERBATIM) {    /* not in verbatim state, still end_verbatim! */
  343.                 verbatim_state = 0;
  344.                 fprintf(stderr, "error in decompression after %d chars [verbatim processing]. skipping...\n", inlen);
  345.                 UNCAST_ERRORS = 1;
  346.             }
  347.             else
  348.             {
  349.             above1:
  350.                 if (c < RESERVED_CHARS) {    /* this is a special-word but not a special char */
  351.                     process_special_char(c)
  352.                 }
  353.                 else {    /* it is an index of a word in the dictionary since 1st byte >= RESERVED_CHARS */
  354.                     index = c;
  355.                     index <<= 8;
  356.                     if ((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  357.                     index |= c;
  358.                     dindex = decode_index(index);
  359.                     if(dindex < MAX_WORDS) {
  360.                         if ((maxoutlen >= 0) && (outlen + AVG_WORD_LEN >= maxoutlen)) return outlen;
  361.                         if (outfp != NULL) outlen += myfpcopy(outfp, compress_string_table[dindex]);
  362.                         if (outbuf != NULL) {
  363.                             outlen += mystrcpy(outbuf+outlen, compress_string_table[dindex]);
  364.                         }
  365.                         if ((maxoutlen >= 0) && (outlen >= maxoutlen)) return outlen;
  366.                     }
  367.                     else {
  368.                         fprintf(stderr, "error in decomperssion after %d chars [bad index %x]. skipping...\n", inlen, index);
  369.                         UNCAST_ERRORS = 1;
  370.                     }
  371.                 }
  372.  
  373.             /* process_char_after_word1: */
  374.                 /* now to see what follows the word: a blank or a special delimiter or not-blank */
  375.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) {
  376.                     if (!TC_FOUND_NOTBLANK) {
  377.                         if (outfp != NULL) putc(' ', outfp);
  378.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  379.                         outlen ++;
  380.                     }
  381.                     TC_FOUND_NOTBLANK = 0;    /* default: use result of previous forward_tcompressed_word only */
  382.                     return outlen;
  383.                 }
  384.                 else if (c < MAX_SPECIAL_CHARS) {
  385.                     if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {
  386.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  387.                         if (outfp != NULL) putc(special_delimiters[c - BEGIN_SPECIAL_DELIMITERS], outfp);
  388.                         if (outbuf != NULL) outbuf[outlen] = special_delimiters[c - BEGIN_SPECIAL_DELIMITERS];
  389.                         outlen ++;
  390.                     }
  391.                     else if (c != NOTBLANK) {
  392.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  393.                         if (outfp != NULL) putc(' ', outfp);
  394.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  395.                         outlen ++;
  396.                         goto bypass_getc1;
  397.                     }
  398.                     /* else go normal getc */
  399.                 }
  400.                 else {    /* can be one of the special_words or a dictionary index */
  401.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  402.                     if (outfp != NULL) putc(' ', outfp);
  403.                     if (outbuf != NULL) outbuf[outlen] = ' ';
  404.                     outlen ++;
  405.                     goto above1;
  406.                 }
  407.             }
  408.         }
  409.     }
  410.     else
  411.     {    /* compression was done in a context sensitive fashion w/o regards to search */
  412.         while(1) {
  413.             if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  414.  
  415.         bypass_getc2:
  416.             if (verbatim_state) {
  417.                 if (c == END_VERBATIM) verbatim_state = 0;
  418.                 else if (c == BEGIN_VERBATIM) goto verbatim_processing;
  419.                 else {
  420.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  421.                     if (outfp != NULL) putc(c, outfp);
  422.                     if (outbuf != NULL) outbuf[outlen] = c;
  423.                     outlen ++;
  424.                 }
  425.             }
  426.             else if (c < END_SPECIAL_CHARS) {
  427.                 process_special_char(c)
  428.                 if ( ((c == NEWLINE) || (c == TWONEWLINES)) && untilnewline)
  429.                 return outlen;
  430.             }
  431.             else if (c == BEGIN_VERBATIM) {
  432.             verbatim_processing:
  433.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  434.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  435.                 if (outfp != NULL) putc(c, outfp);
  436.                 if (outbuf != NULL) outbuf[outlen] = c;
  437.                 outlen ++;
  438.                 if ((c!=BEGIN_VERBATIM) && (c!=END_VERBATIM)) verbatim_state = 1;    /* only _these_ are escape characters */
  439.             }
  440.             else if (c == END_VERBATIM) {    /* not in verbatim state, still end_verbatim! */
  441.                 verbatim_state = 0;
  442.                 fprintf(stderr, "error in decompression after %d chars [verbatim processing]. skipping...\n", inlen);
  443.                 UNCAST_ERRORS = 1;
  444.             }
  445.             else
  446.             {
  447.             above2:
  448.                 if (c < RESERVED_CHARS) {    /* this is a special-word but not a special char */
  449.                     process_special_char(c)
  450.                 }
  451.                 else {    /* it is an index of a word in the dictionary since 1st byte >= RESERVED_CHARS */
  452.                     index = c;
  453.                     index <<= 8;
  454.                     if ((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  455.                     index |= c;
  456.                     dindex = decode_index(index);
  457.                     if(dindex < MAX_WORDS) {
  458.                         if ((maxoutlen >= 0) && (outlen + AVG_WORD_LEN >= maxoutlen)) return outlen;
  459.                         if (outfp != NULL) outlen += myfpcopy(outfp, compress_string_table[dindex]);
  460.                         if (outbuf != NULL) {
  461.                             outlen += mystrcpy(outbuf+outlen, compress_string_table[dindex]);
  462.                         }
  463.                         if ((maxoutlen >= 0) && (outlen >= maxoutlen)) return outlen;
  464.                     }
  465.                     else {
  466.                         fprintf(stderr, "error in decomperssion after %d chars [bad index %x]. skipping...\n", inlen, index);
  467.                         UNCAST_ERRORS = 1;
  468.                     }
  469.                 }
  470.  
  471.             /* process_char_after_word2: */
  472.                 /* now to see what follows the word: a blank or a special delimiter or not-blank */
  473.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) {
  474.                     if (!TC_FOUND_NOTBLANK) {
  475.                         if (outfp != NULL) putc(' ', outfp);
  476.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  477.                         outlen ++;
  478.                     }
  479.                     TC_FOUND_NOTBLANK = 0;    /* default: use result of previous forward_tcompressed_word only */
  480.                     return outlen;
  481.                 }
  482.                 else if (c < MAX_SPECIAL_CHARS) {
  483.                     if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {
  484.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  485.                         if (outfp != NULL) putc(special_delimiters[c - BEGIN_SPECIAL_DELIMITERS], outfp);
  486.                         if (outbuf != NULL) outbuf[outlen] = special_delimiters[c - BEGIN_SPECIAL_DELIMITERS];
  487.                         outlen ++;
  488.                     }
  489.                     else if (c != NOTBLANK) {
  490.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  491.                         if (outfp != NULL) putc(' ', outfp);
  492.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  493.                         outlen ++;
  494.                         goto bypass_getc2;
  495.                     }
  496.                     /* else go normal getc */
  497.                 }
  498.                 else {    /* can be one of the special_words or a dictionary index */
  499.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  500.                     if (outfp != NULL) putc(' ', outfp);
  501.                     if (outbuf != NULL) outbuf[outlen] = ' ';
  502.                     outlen ++;
  503.                     goto above2;
  504.                 }
  505.             }
  506.         }
  507.     }
  508. }
  509.  
  510. #define FUNCTION    tuncompress_file
  511. #define DIRECTORY    tuncompress_directory
  512. #include "trecursive.c"
  513.  
  514. /* returns #bytes (>=0) in the uncompressed file, -1 if major error (not able to uncompress) */
  515. int
  516. tuncompress_file(name, outname, flags)
  517.     char    *name;
  518.     char    *outname;
  519.     int    flags;
  520. {
  521.     FILE    *fp;
  522.     FILE    *outfp;
  523.     int    inlen, ret;
  524.     struct stat statbuf;
  525.     /* struct timeval tvp[2]; */
  526.     struct utimbuf tvp;
  527.  
  528.     if (name == NULL) return -1;
  529.     if (-1 == stat(name, &statbuf)) {
  530.         if (flags & TC_ERRORMSGS)
  531.             fprintf(stderr, "permission denied or non-existent: %s\n", name);
  532.         return -1;
  533.     }
  534.     if (S_ISDIR(statbuf.st_mode)) {
  535.         if (flags & TC_RECURSIVE) return tuncompress_directory(name, outname, flags);
  536.         if (flags & TC_ERRORMSGS)
  537.             fprintf(stderr, "skipping directory: %s\n", name);
  538.         return -1;
  539.     }
  540.         if (!S_ISREG(statbuf.st_mode)) {
  541.                 if (flags & TC_ERRORMSGS)
  542.             fprintf(stderr, "not a regular file, skipping: %s\n", name);
  543.                 return -1;
  544.     }
  545.  
  546.     inlen = strlen(name);
  547.     if (!tuncompressible_filename(name, inlen)) {
  548.         if (!(flags & TC_RECURSIVE) && (flags & TC_ERRORMSGS))
  549.             fprintf(stderr, "no %s extension, skipping: %s\n", COMP_SUFFIX, name);
  550.         return -1;
  551.     }
  552.     if ((fp = fopen(name, "r")) == NULL) {
  553.         if (flags & TC_ERRORMSGS)
  554.             fprintf(stderr, "permission denied or non-existent: %s\n", name);
  555.         return -1;
  556.     }
  557.     if (!tuncompressible_fp(fp)) {
  558.         if (flags & TC_ERRORMSGS)
  559.             fprintf(stderr, "signature does not match, skipping: %s\n", name);
  560.         fclose(fp);
  561.         return -1;
  562.     }
  563.     if (flags & TC_SILENT) {
  564.         printf("%s\n", name);
  565.         fclose(fp);
  566.         return 0;
  567.     }
  568.  
  569.     /* Create and open output file */
  570.     strncpy(outname, name, MAX_LINE_LEN);
  571.     outname[inlen - strlen(COMP_SUFFIX)] = '\0';
  572.     if (!access(outname, R_OK)) {
  573.         if (!(flags & TC_OVERWRITE)) {
  574.             fclose(fp);
  575.             return 0;
  576.         }
  577.         else if (!(flags & TC_NOPROMPT)) {
  578.             char    s[8];
  579.             printf("overwrite %s? (y/n): ", outname);
  580.             scanf("%c", s);
  581.             if (s[0] != 'y') {
  582.                 fclose(fp);
  583.                 return 0;
  584.             }
  585.         }
  586.     }
  587.     if ((outfp = fopen(outname, "w")) == NULL) {
  588.         if (flags & TC_ERRORMSGS)
  589.             fprintf(stderr, "cannot open for writing: %s\n", outname);
  590.         fclose(fp);
  591.         return -1;
  592.     }
  593.  
  594.     UNCAST_ERRORS = 0;
  595.     if ( ((ret = tuncompress(fp, -1, outfp, -1, flags)) > 0) && !UNCAST_ERRORS && (flags & TC_REMOVE)) {
  596.         unlink(name);
  597.     }
  598.  
  599.     fclose(fp);
  600.     fflush(outfp);
  601.     fclose(outfp);
  602.     /*
  603.     tvp[0].tv_sec = statbuf.st_atime;
  604.     tvp[0].tv_usec = 0;
  605.     tvp[1].tv_sec = statbuf.st_mtime;
  606.     tvp[1].tv_usec = 0;
  607.     utimes(outname, tvp);
  608.     */
  609.     tvp.actime = statbuf.st_atime;
  610.     tvp.modtime = statbuf.st_mtime;
  611.     utime(outname, &tvp);
  612.     return ret;
  613. }
  614.